home *** CD-ROM | disk | FTP | other *** search
/ Aminet 28 / Aminet 28 (1998)(GTI - Schatztruhe)[!][Dec 1998].iso / Aminet / util / libs / PalmLink.lha / PalmLink / examples / PalmTransfer.c < prev   
Encoding:
C/C++ Source or Header  |  1998-09-10  |  21.0 KB  |  881 lines

  1. /*********************************************************************
  2. **                                                                  **
  3. **        PalmTransfer    -- Data dialog between Amiga and Palm     **
  4. **                                                                  **
  5. *********************************************************************/
  6. /*
  7. **  Copyright © 1998 Richard Körber  --  All Rights Reserved
  8. **    E-Mail: shred@eratosthenes.starfleet.de
  9. **    URL:    http://shredzone.home.pages.de
  10. **
  11. ***************************************************************/
  12. /*
  13. **  This program is free software; you can redistribute it and/or modify
  14. **  it under the terms of the GNU General Public License as published by
  15. **  the Free Software Foundation; either version 2 of the License, or
  16. **  any later version.
  17. **
  18. **  This program is distributed in the hope that it will be useful,
  19. **  but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21. **  GNU General Public License for more details.
  22. **
  23. **  You should have received a copy of the GNU General Public License
  24. **  along with this program; if not, write to the Free Software
  25. **  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  26. **
  27. **  The author (Richard Körber) reserves the right to revoke the
  28. **  GNU General Public License whenever he feels that it is necessary,
  29. **  especially when he found out that the licence has been abused,
  30. **  ignored or violated, and without prior notice.
  31. **
  32. **  You must not use this source code to gain profit of any kind!
  33. **
  34. ***************************************************************/
  35. /*
  36. **  Compiles with SAS/C, e.g.
  37. **      sc PalmTransfer.c NOSTACKCHECK DATA=NEAR STRMER CPU=68060 OPT
  38. */
  39.  
  40. #include <stdio.h>
  41. #include <string.h>
  42. #include <clib/alib_protos.h>
  43. #include <clib/exec_protos.h>
  44. #include <clib/dos_protos.h>
  45. #include <clib/utility_protos.h>
  46. #include <clib/palmlink_protos.h>
  47. #include <pragmas/exec_pragmas.h>
  48. #include <pragmas/dos_pragmas.h>
  49. #include <pragmas/utility_pragmas.h>
  50. #include <pragmas/palmlink_pragmas.h>
  51. #include <exec/memory.h>
  52. #include <dos/dos.h>
  53. #include <dos/dosasl.h>
  54. #include <libraries/palmlink.h>
  55.  
  56.  
  57. #define  VERSIONSTR   "1.0"
  58. #define  DATESTR      "10.9.98"
  59. #define  COPYRIGHTSTR "1998"
  60. #define  EMAILSTR     "shred@eratosthenes.starfleet.de"
  61. #define  URLSTR       "http://shredzone.home.pages.de"
  62.  
  63. #define  NORMAL       "\2330m"
  64. #define  BOLD         "\2331m"
  65. #define  ITALIC       "\2333m"
  66. #define  UNDERLINE    "\2334m"
  67.  
  68. #define  MKTAG(a,b,c,d)  ((ULONG) (a)<<24 | (ULONG) (b)<<16 | (ULONG) (c)<<8 | (ULONG) (d))
  69.  
  70. static char ver[] = "$VER: PalmTransfer " VERSIONSTR " (" DATESTR ") " EMAILSTR;
  71. static char titletxt[] = \
  72.   BOLD "PalmTransfer " VERSIONSTR " (C) " COPYRIGHTSTR " Richard Körber -- all rights reserved" NORMAL "\n\n";
  73. static char helptxt[] = \
  74.   "  " ITALIC "E-Mail: " NORMAL EMAILSTR "\n"
  75.   "  " ITALIC "URL:    " NORMAL URLSTR "\n\n"
  76.   ITALIC "Usage:" NORMAL "\n"
  77.   "  BACKUP/S       Backup the database (DIR)\n"
  78.   "  RESTORE/S      Restore a backup (DIR)\n"
  79.   "  INSTALL/S      Install a file (FILE)\n"
  80.   "  MERGE/S        Merge a file (FILE)\n"
  81.   "  FETCH/S        Fetch a database (NAME)\n"
  82.   "  DELETE/S       Delete a database (NAME)\n"
  83.   "  LIST/S         List all databases\n"
  84.   "  PURGE/S        Purge deleted records\n"
  85.   "  DIR/K          Backup directory (if required)\n"
  86.   "  FILE/K         Filename (if required)\n"
  87.   "  NAME/K         Database name (if required)\n"
  88.   "  DEVICE/K       Serial device (\"serial.device\")\n"
  89.   "  UNIT/K/N       Serial unit (0)\n"
  90.   "  MAXBAUD/K/N    Maximum baud (28800)\n"
  91.   "\n";
  92.  
  93. struct Parameter
  94. {
  95.   LONG   backup;
  96.   LONG   restore;
  97.   LONG   install;
  98.   LONG   merge;
  99.   LONG   fetch;
  100.   LONG   delete;
  101.   LONG   list;
  102.   LONG   purge;
  103.   STRPTR dir;
  104.   STRPTR file;
  105.   STRPTR name;
  106.   STRPTR device;
  107.   LONG   *unit;
  108.   LONG   *maxbaud;
  109. }
  110. param;
  111.  
  112. static char template[] = "BACKUP/S,RESTORE/S,INSTALL/S,MERGE/S,FETCH/S,DELETE/S,LIST/S,PURGE/S,D=DIR/K,F=FILE/K,N=NAME/K,SD=DEVICE/K,SU=UNIT/K/N,SB=MAXBAUD/K/N";
  113.  
  114. struct FileNode
  115. {
  116.   struct Node Node;         // Backup/Restore
  117.   struct DateStamp Date;    // Backup only
  118.   struct DLP_DBInfo dbinfo; // Restore only
  119.   char FileName[108];       // Backup/Restore
  120. };
  121.  
  122. extern struct DOSBase *DOSBase;
  123. struct Library *PalmlinkBase;
  124. struct Library *UtilityBase;
  125. APTR socket = NULL;
  126. BOOL ignoreError = FALSE;
  127.  
  128.  
  129.  
  130. /*
  131. ** get last error code as string
  132. */
  133. STRPTR getError(APTR socket)
  134. {
  135.   static unsigned char errortext[256];
  136.   PL_Explain(PL_LastError(socket),errortext,255);
  137.   return(errortext);
  138. }
  139.  
  140. /*
  141. ** Open a connection to the Pilot
  142. */
  143. int Connect(void)
  144. {
  145.   LONG error;
  146.  
  147.   if(socket) return(TRUE);
  148.  
  149.   socket = PL_OpenSocketTags
  150.     (
  151.     PLTAG_ErrorPtr      , &error,
  152.     PLTAG_SerialDevice  , (param.device  ? param.device   : (unsigned char *)"serial.device"),
  153.     PLTAG_SerialUnit    , (param.unit    ? *param.unit    : 0),
  154.     PLTAG_SerialMaxRate , (param.maxbaud ? *param.maxbaud : 28800),
  155.     PLTAG_AbortMask     , SIGBREAKF_CTRL_C,
  156.     TAG_DONE
  157.     );
  158.  
  159.   if(socket)
  160.   {
  161.     Printf("Please press the HotSync button " ITALIC "now" NORMAL "\n");
  162.     return(PL_Accept(socket,10L));
  163.   }
  164.   else
  165.   {
  166.     unsigned char errortext[256];
  167.     PL_Explain(error,errortext,255);
  168.     Printf("** Socket error: %s\n",errortext);
  169.   }
  170.   return(FALSE);
  171. }
  172.  
  173. /*
  174. ** Close all databases and disconnect
  175. */
  176. void Disconnect(void)
  177. {
  178.   if(!socket) return;
  179.   DLP_AddSyncLogEntry(socket,"Synchronized with PalmLink\n-- AMIGA made it possible --\n");
  180.   DLP_EndOfSync(socket,0);
  181.   PL_CloseSocket(socket);
  182. }
  183.  
  184. /*
  185. ** Generate a AmigaDOS conformous file name from the
  186. ** DataBase name.
  187. */
  188. void genFileName(STRPTR name, struct DLP_DBInfo *dbinfo)
  189. {
  190.   UWORD i;
  191.  
  192.   strcpy(name,dbinfo->name);
  193.   for(i=0; i<strlen(name); i++)
  194.     if(name[i]<' ' || name[i]=='/' || name[i]==':') name[i]='_';  // Protect DOS characters
  195.   if(dbinfo->flags & DLPDBIF_RESOURCE)
  196.     strcat(name,".prc");
  197.   else
  198.     strcat(name,".pdb");
  199. }
  200.  
  201.  
  202. /*
  203. ** Convert a DLP_SysTime to a DOS DateStamp
  204. */
  205. void Date2Stamp(struct DLP_SysTime *time, struct DateStamp *ds)
  206. {
  207.   struct ClockData cld;
  208.   ULONG sec;
  209.  
  210.   cld.year  = time->year;
  211.   cld.month = time->month;
  212.   cld.mday  = time->day;
  213.   cld.hour  = time->hour;
  214.   cld.min   = time->minute;
  215.   cld.sec   = time->second;
  216.   sec = Date2Amiga(&cld);
  217.  
  218.   ds->ds_Tick   = (sec%60) * TICKS_PER_SECOND;
  219.   sec /= 60;
  220.   ds->ds_Minute = sec%(24*60);
  221.   sec /= 24*60;
  222.   ds->ds_Days   = sec;
  223. }
  224.  
  225. /*
  226. ** Convert a DOS DateStamp to DLP_SysTime
  227. */
  228. void Stamp2Date(struct DateStamp *ds, struct DLP_SysTime *time)
  229. {
  230.   struct ClockData cld;
  231.  
  232.   Amiga2Date(((ds->ds_Days*24*60)+ds->ds_Minute)*60+(ds->ds_Tick/TICKS_PER_SECOND),&cld);
  233.   time->year   = cld.year;
  234.   time->month  = cld.month;
  235.   time->day    = cld.mday;
  236.   time->hour   = cld.hour;
  237.   time->minute = cld.min;
  238.   time->second = cld.sec;
  239. }
  240.  
  241. /*
  242. ** Set a DLP_SysTime to the current date and time
  243. */
  244. void setToday(struct DLP_SysTime *time)
  245. {
  246.   struct DateStamp ds;
  247.   DateStamp(&ds);
  248.   Stamp2Date(&ds,time);
  249. }
  250.  
  251.  
  252. /*
  253. ** Set the Pilot into a synchronized state
  254. */
  255. void VoidSyncFlags(void)
  256. {
  257.   struct DLP_UserInfo user;
  258.   if(Connect())
  259.   {
  260.     if(DLP_GetUserInfo(socket,&user))
  261.     {
  262.       user.lastSyncPC = 0x00000000;     // Hopefully unique...
  263.       setToday(&user.successfulSync);
  264.       setToday(&user.lastSync);
  265.       DLP_SetUserInfo(socket,&user);
  266.     }
  267.   }
  268. }
  269.  
  270.  
  271. /*
  272. ** Backup a database
  273. */
  274. void cmd_backup(STRPTR dir)
  275. {
  276.   APTR fh;
  277.   BPTR lock;
  278.   BPTR olddir;
  279.   struct FileInfoBlock *fib;
  280.   struct List files;
  281.   struct FileNode *newnode;
  282.   struct FileNode *currEntry, *nextEntry;
  283.   struct DLP_DBInfo dbinfo;
  284.   struct DLP_SysTime time;
  285.   struct DateStamp stamp;
  286.  
  287.   UWORD i;
  288.   char filename[100];
  289.  
  290.   NewList(&files);
  291.  
  292.   if(!dir)
  293.   {
  294.     PutStr("** DIR required\n");
  295.     return;
  296.   }
  297.  
  298.   /* Check if existing, and if it is really a directory */
  299.   if(!(fib = AllocVec(sizeof(struct FileInfoBlock),MEMF_PUBLIC))) return;
  300.   lock = Lock(dir,ACCESS_READ);
  301.   if(!lock)                             // Does not exist, so create it
  302.   {
  303.     lock = CreateDir(dir);
  304.     if(!lock)                           // Couldn't create either
  305.     {
  306.       Printf("** Couldn't create directory %s\n",dir);
  307.       FreeVec(fib);
  308.       return;
  309.     }
  310.   }
  311.  
  312.   if(!Examine(lock,fib))
  313.   {
  314.     Printf("** Couldn't examine directory %s\n",dir);
  315.     goto error;
  316.   }
  317.   if(fib->fib_DirEntryType < 0)
  318.   {
  319.     Printf("** %s is not a directory\n",dir);
  320.     goto error;
  321.   }
  322.  
  323.   olddir = CurrentDir(lock);
  324.  
  325.   /* Read all file names into the files list */
  326.   while(ExNext(lock,fib))
  327.   {
  328.     if(fib->fib_DirEntryType > 0) continue;   // Skip subdirectories
  329.  
  330.     newnode = AllocVec(sizeof(struct FileNode),MEMF_ANY);
  331.     if(!newnode) goto error;
  332.  
  333.     CopyMem(fib->fib_FileName,newnode->FileName,108);
  334.     CopyMem(&fib->fib_Date,&newnode->Date,sizeof(struct DateStamp));
  335.     newnode->Node.ln_Name = newnode->FileName;
  336.     AddTail(&files,(struct Node *)newnode);
  337.   }
  338.  
  339.   /* Open conduit */
  340.   if(!Connect()) goto error;
  341.  
  342.   /* Backup all database entries */
  343.   for(i=0;;)
  344.   {
  345.     if(!DLP_OpenConduit(socket)) goto error;
  346.     if(!DLP_GetDBInfo(socket,0,DLPGDBF_RAM,i,&dbinfo))    // get the next entry
  347.     {
  348.       if(PL_LastError(socket)==PLERR_NOTFOUND) break;     // last one
  349.       goto error;
  350.     }
  351.     i = dbinfo.index+1;
  352.     genFileName(filename,&dbinfo);
  353.     newnode = (struct FileNode *)FindName(&files,filename);   // search for the file
  354.     if(newnode)                                           // File does already exist
  355.     {
  356.       Stamp2Date(&newnode->Date,&time);                   // Check if the file has
  357.       if(  (time.year   == dbinfo.modifyDate.year)        // not been modified since
  358.          &&(time.month  == dbinfo.modifyDate.month)       // last backup
  359.          &&(time.day    == dbinfo.modifyDate.day)
  360.          &&(time.hour   == dbinfo.modifyDate.hour)
  361.          &&(time.minute == dbinfo.modifyDate.minute)
  362.          &&(time.second == dbinfo.modifyDate.second))
  363.       {
  364.         Printf("  Skipped: %s (not changed)\n",newnode->FileName);
  365.         Remove((struct Node *)newnode);                   // yes: skip it
  366.         FreeVec(newnode);
  367.         continue;
  368.       }
  369.     }
  370.  
  371.     /* Retrieve the file */
  372.     dbinfo.flags &= ~DLPDBIF_OPEN;                        // Saved database is not open
  373.  
  374.     fh = PL_FileOpen(filename,&dbinfo);
  375.     if(!fh)
  376.     {
  377.       Printf("** Unable to open file %s for writing\n",filename);
  378.       goto error;
  379.     }
  380.     Printf("  Store:   %s (from %s)... ",filename,dbinfo.name);
  381.     Flush(Output());
  382.     if(PL_FileRetrieve(fh,socket,0))                      // Get the file
  383.       PutStr("OK\n");
  384.     else
  385.       Printf("Failed (%s)\n",getError(socket));
  386.     PL_FileClose(fh);
  387.  
  388.     Date2Stamp(&dbinfo.modifyDate,&stamp);                // Set file date to the
  389.     SetFileDate(filename,&stamp);                         // last modification date
  390.  
  391.     if(newnode)
  392.     {
  393.       Remove((struct Node *)newnode);                     // Remove from list
  394.       FreeVec(newnode);
  395.     }
  396.   }
  397.  
  398.   /* Delete all remaining files */
  399.   for
  400.   (
  401.     currEntry=(struct FileNode *)files.lh_Head;
  402.     nextEntry=(struct FileNode *)currEntry->Node.ln_Succ;
  403.     currEntry=nextEntry
  404.   )
  405.   {
  406.     Printf("  Delete:  %s...\n",currEntry->FileName);     // Is deleted on the Pilot too
  407.     Flush(Output());
  408.     if(DeleteFile(currEntry->FileName))
  409.       PutStr("OK\n");
  410.     else
  411.       Printf("Failed (%s)\n",getError(socket));
  412.     Remove((struct Node *)currEntry);
  413.     FreeVec(currEntry);
  414.   }
  415.  
  416.   VoidSyncFlags();                                        // Sync done
  417.  
  418.   PutStr("Backup completed successfully\n");
  419.  
  420. error:
  421.   if(PL_LastError(socket)==PLERR_NOTFOUND) ignoreError = TRUE;
  422.   CurrentDir(olddir);
  423.   for                                                     // Clean up all memory
  424.   (
  425.     currEntry=(struct FileNode *)files.lh_Head;
  426.     nextEntry=(struct FileNode *)currEntry->Node.ln_Succ;
  427.     currEntry=nextEntry
  428.   )
  429.   {
  430.     Remove((struct Node *)currEntry),
  431.     FreeVec(currEntry);
  432.   }
  433.   FreeVec(fib);                         // Release FIB
  434.   UnLock(lock);                         // Free directory lock
  435.   return;
  436. }
  437.  
  438. /*
  439. ** Restore a database
  440. */
  441. void cmd_restore(STRPTR dir)
  442. {
  443.   APTR fh;
  444.   BPTR lock;
  445.   BPTR olddir;
  446.   struct FileInfoBlock *fib;
  447.   struct List files;
  448.   struct FileNode *newnode;
  449.   struct FileNode *currEntry, *nextEntry;
  450.  
  451.   NewList(&files);
  452.  
  453.   if(!dir)
  454.   {
  455.     PutStr("** DIR required\n");
  456.     return;
  457.   }
  458.  
  459.   /* Check if existing, and if it is really a directory */
  460.   if(!(fib = AllocVec(sizeof(struct FileInfoBlock),MEMF_PUBLIC))) return;
  461.   lock = Lock(dir,ACCESS_READ);
  462.   if(!lock)                             // Does not exist
  463.   {
  464.     Printf("** Couldn't find directory %s\n",dir);
  465.     FreeVec(fib);
  466.     return;
  467.   }
  468.  
  469.   if(!Examine(lock,fib))
  470.   {
  471.     Printf("** Couldn't examine directory %s\n",dir);
  472.     goto error;
  473.   }
  474.   if(fib->fib_DirEntryType < 0)
  475.   {
  476.     Printf("** %s is not a directory\n",dir);
  477.     goto error;
  478.   }
  479.  
  480.   olddir = CurrentDir(lock);            // Set as current dir
  481.  
  482.   /* Read all file names into the files list */
  483.   while(ExNext(lock,fib))
  484.   {
  485.     if(fib->fib_DirEntryType > 0) continue;   // Skip subdirectories
  486.  
  487.     newnode = AllocVec(sizeof(struct FileNode),MEMF_ANY);
  488.     if(!newnode) goto error;
  489.  
  490.     CopyMem(fib->fib_FileName,newnode->FileName,108);
  491.     newnode->Node.ln_Name = newnode->FileName;
  492.     CopyMem(&fib->fib_Date,&newnode->Date,sizeof(struct DateStamp));
  493.  
  494.     fh = PL_FileOpen(newnode->FileName,NULL);
  495.     if(!fh)
  496.     {
  497.       Printf("** Unable to open file %s for reading\n",newnode->FileName);
  498.       goto error;
  499.     }
  500.     CopyMem(PL_FileGetDBInfo(fh),&newnode->dbinfo,sizeof(struct DLP_DBInfo));
  501.     PL_FileClose(fh);
  502.  
  503.     if(newnode->dbinfo.type == MKTAG('a','p','p','l'))
  504.       AddTail(&files,(struct Node *)newnode);         // send 'appl' as last
  505.     else
  506.       AddHead(&files,(struct Node *)newnode);
  507.   }
  508.  
  509.   /* Open connection */
  510.   if(!Connect()) goto error;
  511.  
  512.   /* Restore all database files */
  513.   for
  514.   (
  515.     currEntry=(struct FileNode *)files.lh_Head;
  516.     nextEntry=(struct FileNode *)currEntry->Node.ln_Succ;
  517.     currEntry=nextEntry
  518.   )
  519.   {
  520.     if(!DLP_OpenConduit(socket)) goto error;
  521.     fh = PL_FileOpen(currEntry->FileName,NULL);
  522.     if(!fh)
  523.     {
  524.       Printf("** Unable to open file %s\n",currEntry->FileName);
  525.       goto error;
  526.     }
  527.     Printf("  Restore: %s as %s...",currEntry->FileName,currEntry->dbinfo.name);
  528.     Flush(Output());
  529.     if(PL_FileInstall(fh,socket,0))
  530.       PutStr("OK\n");
  531.     else
  532.       Printf("Failed (%s)\n",getError(socket));
  533.     PL_FileClose(fh);
  534.     Remove((struct Node *)currEntry);
  535.     FreeVec(currEntry);
  536.   }
  537.  
  538.   PutStr("Restore completed successfully\n");
  539.   VoidSyncFlags();                                        // Sync done
  540.  
  541. error:
  542.   if(PL_LastError(socket)==PLERR_NOTFOUND) ignoreError = TRUE;
  543.   CurrentDir(olddir);
  544.   for                                                     // Clean up all memory
  545.   (
  546.     currEntry=(struct FileNode *)files.lh_Head;
  547.     nextEntry=(struct FileNode *)currEntry->Node.ln_Succ;
  548.     currEntry=nextEntry
  549.   )
  550.   {
  551.     Remove((struct Node *)currEntry),
  552.     FreeVec(currEntry);
  553.   }
  554.   FreeVec(fib);                         // Release FIB
  555.   UnLock(lock);                         // Free directory lock
  556.   return;
  557. }
  558.  
  559.  
  560. /*
  561. ** Install a software
  562. */
  563. void cmd_install(STRPTR file)
  564. {
  565.   APTR fh;
  566.  
  567.   if(!file)
  568.   {
  569.     PutStr("** FILE required\n");
  570.     return;
  571.   }
  572.  
  573.   if(!Connect()) return;
  574.   if(!DLP_OpenConduit(socket)) return;
  575.  
  576.   fh = PL_FileOpen(file,NULL);
  577.   if(!fh)
  578.   {
  579.     Printf("** Unable to open file %s\n",file);
  580.     return;
  581.   }
  582.   Printf("Installing %s...",file);
  583.   Flush(Output());
  584.   if(PL_FileInstall(fh,socket,0))
  585.     PutStr("OK\n");
  586.   else
  587.     Printf("Failed (%s)\n",getError(socket));
  588.  
  589.   PL_FileClose(fh);
  590.   VoidSyncFlags();
  591. }
  592.  
  593. /*
  594. ** Merge a software
  595. */
  596. void cmd_merge(STRPTR file)
  597. {
  598.   APTR fh;
  599.  
  600.   if(!file)
  601.   {
  602.     PutStr("** FILE required\n");
  603.     return;
  604.   }
  605.  
  606.   if(!Connect()) return;
  607.   if(!DLP_OpenConduit(socket)) return;
  608.  
  609.   fh = PL_FileOpen(file,NULL);
  610.   if(!fh)
  611.   {
  612.     Printf("** Unable to open file %s\n",file);
  613.     return;
  614.   }
  615.   Printf("Merging %s...",file);
  616.   Flush(Output());
  617.   if(PL_FileMerge(fh,socket,0))
  618.     PutStr("OK\n");
  619.   else
  620.     Printf("Failed (%s)\n",getError(socket));
  621.  
  622.   PL_FileClose(fh);
  623.   VoidSyncFlags();
  624. }
  625.  
  626. /*
  627. ** Fetch a database
  628. */
  629. void cmd_fetch(STRPTR name)
  630. {
  631.   struct DLP_DBInfo dbinfo;
  632.   UWORD index;
  633.   BOOL found;
  634.   char filename[50];
  635.   APTR fh;
  636.  
  637.   if(!name)
  638.   {
  639.     PutStr("** NAME required\n");
  640.     return;
  641.   }
  642.  
  643.   if(!Connect()) return;
  644.   if(!DLP_OpenConduit(socket)) return;
  645.  
  646.   for(found=TRUE, index=0;;)
  647.   {
  648.     if(DLP_GetDBInfo(socket,0,DLPGDBF_RAM,index,&dbinfo))
  649.     {
  650.       if(!strcmp(name,dbinfo.name)) break;
  651.       index = dbinfo.index+1;
  652.     }
  653.     else
  654.     {
  655.       found=FALSE;
  656.       break;
  657.     }
  658.   }
  659.  
  660.   if(!found)
  661.     for(found=TRUE, index=0;;)
  662.     {
  663.       if(DLP_GetDBInfo(socket,0,DLPGDBF_ROM,index,&dbinfo))
  664.       {
  665.         if(!strcmp(name,dbinfo.name)) break;
  666.         index = dbinfo.index+1;
  667.       }
  668.       else
  669.       {
  670.         found=FALSE;
  671.         break;
  672.       }
  673.     }
  674.  
  675.   if(!found)
  676.   {
  677.     Printf("** Database %s not found\n",name);
  678.     return;
  679.   }
  680.  
  681.   genFileName(filename,&dbinfo);
  682.  
  683.   dbinfo.flags &= ~DLPDBIF_OPEN;      // Saved database is not open
  684.  
  685.   fh = PL_FileOpen(filename,&dbinfo);
  686.   if(!fh)
  687.   {
  688.     Printf("** Unable to open file %s\n",filename);
  689.     return;
  690.   }
  691.  
  692.   Printf("Fetching %s to file %s... ",name,filename);
  693.   Flush(Output());
  694.   if(PL_FileRetrieve(fh,socket,0))
  695.     PutStr("OK\n");
  696.   else
  697.     Printf("Failed (%s)\n",getError(socket));
  698.  
  699.   PL_FileClose(fh);
  700. }
  701.  
  702. /*
  703. ** Delete a database
  704. */
  705. void cmd_delete(STRPTR name)
  706. {
  707.   struct DLP_DBInfo dbinfo = {0};
  708.   UWORD index;
  709.   BOOL found;
  710.  
  711.   if(!name)
  712.   {
  713.     PutStr("** NAME required\n");
  714.     return;
  715.   }
  716.  
  717.   if(!Connect()) return;
  718.   if(!DLP_OpenConduit(socket)) return;
  719.  
  720.   for(found=TRUE, index=0;;)
  721.   {
  722.     if(DLP_GetDBInfo(socket,0,DLPGDBF_RAM,index,&dbinfo))
  723.     {
  724.       if(!strcmp(name,dbinfo.name)) break;
  725.       index = dbinfo.index+1;
  726.     }
  727.     else
  728.     {
  729.       found=FALSE;
  730.       break;
  731.     }
  732.   }
  733.  
  734.   if(!found)
  735.   {
  736.     Printf("** Database %s not found\n",name);
  737.     return;
  738.   }
  739.  
  740.   Printf("Deleting %s... ",name);
  741.   Flush(Output());
  742.  
  743.   if(!DLP_DeleteDB(socket,0,name))
  744.   {
  745.     Printf("Failed (%s)\n",getError(socket));
  746.     return;
  747.   }
  748.  
  749.   PutStr("OK\n");
  750.  
  751.   if(dbinfo.type==MKTAG('b','o','o','t')) PutStr("Rebooting after HotSync.\n");
  752. }
  753.  
  754. /*
  755. ** List all databases
  756. */
  757. void cmd_list(void)
  758. {
  759.   struct DLP_DBInfo info;
  760.   UWORD i;
  761.   ULONG nr;
  762.  
  763.   if(!Connect()) return;
  764.   if(!DLP_OpenConduit(socket)) return;
  765.  
  766.   PutStr(BOLD "-- LIST OF ALL RAM DATABASES --" NORMAL "\n");
  767.  
  768.   for(nr=1,i=0 ; ; nr++)
  769.   {
  770.     if(!DLP_GetDBInfo(socket,0,DLPGDBF_RAM,i,&info)) break;
  771.     Printf("%3ld: '%s'\n",nr,info.name);
  772.     i = info.index+1;
  773.   }
  774.  
  775.   PutStr(BOLD "-- LIST OF ALL ROM DATABASES --" NORMAL "\n");
  776.  
  777.   for(nr=1,i=0 ; ; nr++)
  778.   {
  779.     if(!DLP_GetDBInfo(socket,0,DLPGDBF_ROM,i,&info)) break;
  780.     Printf("%3ld: '%s'\n",nr,info.name);
  781.     i = info.index+1;
  782.   }
  783.  
  784.   PutStr(BOLD "---------------------------" NORMAL "\n");
  785.   if(PL_LastError(socket)==PLERR_NOTFOUND) ignoreError = TRUE;
  786. }
  787.  
  788. /*
  789. ** Purge all deleted records
  790. */
  791. void cmd_purge(void)
  792. {
  793.   struct DLP_DBInfo info;
  794.   UWORD i;
  795.   LONG dbh;
  796.  
  797.   if(!Connect()) return;
  798.   if(!DLP_OpenConduit(socket)) return;
  799.  
  800.   PutStr(BOLD "Purging deleted records from..." NORMAL "\n");
  801.  
  802.   for(i=0;;)
  803.   {
  804.     if(!DLP_GetDBInfo(socket,0,DLPGDBF_RAM,i,&info)) break;
  805.     i = info.index+1;
  806.     if(info.flags & DLPDBIF_RESOURCE) continue;       // don't purge resources
  807.     Printf("  %s: ",info.name);
  808.     Flush(Output());
  809.     dbh = DLP_OpenDB(socket,0,DLPDBOF_READWRITE,info.name);
  810.     if(   dbh>=0
  811.        && DLP_CleanUpDatabase(socket,dbh)
  812.        && DLP_ResetSyncFlags(socket,dbh))
  813.     {
  814.       PutStr("OK\n");
  815.       DLP_CloseDB(socket,dbh);
  816.     }
  817.     else
  818.     {
  819.       Printf("Failed (%s)\n",getError(socket));
  820.     }
  821.   }
  822.   if(PL_LastError(socket)==PLERR_NOTFOUND) ignoreError = TRUE;
  823.   VoidSyncFlags();
  824. }
  825.  
  826. /*
  827. ** MAIN PART
  828. */
  829. int main(void)
  830. {
  831.   struct RDArgs *args;
  832.  
  833.   PutStr(titletxt);
  834.  
  835.   if(args = (struct RDArgs *)ReadArgs(template,(LONG *)¶m,NULL))
  836.   {
  837.     if(UtilityBase = OpenLibrary("utility.library",36L))
  838.     {
  839.       if(PalmlinkBase = OpenLibrary("palmlink.library",1L))
  840.       {
  841.         if(param.backup)                  // BACKUP
  842.           cmd_backup(param.dir);
  843.         else if(param.restore)            // RESTORE
  844.           cmd_restore(param.dir);
  845.         else if(param.install)            // INSTALL
  846.           cmd_install(param.file);
  847.         else if(param.merge)              // MERGE
  848.           cmd_merge(param.file);
  849.         else if(param.fetch)              // FETCH
  850.           cmd_fetch(param.name);
  851.         else if(param.delete)             // DELETE
  852.           cmd_delete(param.name);
  853.         else if(param.list)               // LIST
  854.           cmd_list();
  855.         else if(param.purge)              // PURGE
  856.           cmd_purge();
  857.         else
  858.           PutStr(helptxt);                // No command was given
  859.  
  860.         if(socket)
  861.         {
  862.           if(!ignoreError && (PL_LastError(socket)!=0))
  863.             Printf("** Socket error: %s\n",getError(socket));
  864.           Disconnect();
  865.         }
  866.         CloseLibrary(PalmlinkBase);
  867.       }
  868.       else PutStr("** Couldn't open palmlink.library V1+\n");
  869.       CloseLibrary(UtilityBase);
  870.     }
  871.     else PutStr("** Couldn't open utility.library V36+\n");
  872.  
  873.     FreeArgs(args);
  874.   }
  875.   else PutStr(helptxt);
  876.  
  877.   return(0);
  878. }
  879.  
  880. /********************************************************************/
  881.